/*
 * Copyright © 2025 上海火金网络科技有限公司. All rights reserved.
 *
 * ✅ MANUAL FILE - CAN BE MODIFIED 手动文件 - 可以修改 ✅
 */

package cn.com.anypay.manager.miaoma.sysoperationlog.aspect;

import cn.com.anypay.manager.miaoma.sysoperationlog.annotation.OperationLog;
import cn.com.anypay.manager.miaoma.sysoperationlog.SysOperationLogService;
import cn.com.anypay.manager.miaoma.sysuser.SysUserService;
import cn.com.anypay.manager.miaoma.sysuser.SysUserEntity;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 操作日志AOP切面
 * 自动记录用户操作日志
 */
@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private SysOperationLogService sysOperationLogService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切点：所有标注了@OperationLog注解的方法
     */
    @Pointcut("@annotation(cn.com.anypay.manager.miaoma.sysoperationlog.annotation.OperationLog)")
    public void operationLogPointcut() {
    }

    /**
     * 环绕通知：记录操作日志
     */
    @Around("operationLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        Exception exception = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            try {
                // 记录操作日志
                recordOperationLog(joinPoint, result, exception, startTime);
            } catch (Exception e) {
                log.error("记录操作日志失败", e);
            }
        }
    }

    /**
     * 记录操作日志
     */
    private void recordOperationLog(ProceedingJoinPoint joinPoint, Object result, 
                                   Exception exception, long startTime) {
        try {
            // 获取注解信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLog operationLog = method.getAnnotation(OperationLog.class);

            if (operationLog == null) {
                return;
            }

            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }

            HttpServletRequest request = attributes.getRequest();

            // 计算执行时间
            long endTime = System.currentTimeMillis();
            int executionTime = (int) (endTime - startTime);

            // 获取用户信息
            Long userId = getCurrentUserId();
            SysUserEntity currentUser = getCurrentUser(userId);
            String username = currentUser != null ? currentUser.getUsername() : "unknown";
            String realName = currentUser != null ? currentUser.getRealName() : "未知用户";

            // 获取操作信息
            String operationModule = operationLog.module();
            String operationType = operationLog.type();
            String operationName = operationLog.name();
            String operationDesc = buildOperationDesc(operationLog, exception);

            // 获取请求参数
            String requestParams = "";
            if (operationLog.recordParams()) {
                requestParams = getRequestParams(joinPoint, request);
            }

            // 获取业务信息
            String businessType = operationLog.businessType();
            String businessId = extractBusinessId(joinPoint, operationLog);
            String businessName = extractBusinessName(joinPoint, operationLog);

            // 记录操作日志
            sysOperationLogService.recordOperationLog(
                userId, username, realName, operationModule, operationType, operationName,
                operationDesc, businessId, businessType, businessName, requestParams, 
                executionTime, operationLog.riskLevel(), request
            );

        } catch (Exception e) {
            log.error("记录操作日志时发生异常", e);
        }
    }

    /**
     * 构建操作描述
     */
    private String buildOperationDesc(OperationLog operationLog, Exception exception) {
        StringBuilder desc = new StringBuilder(operationLog.description());
        
        if (exception != null) {
            desc.append(" - 操作失败: ").append(exception.getMessage());
        } else {
            desc.append(" - 操作成功");
        }
        
        return desc.toString();
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        try {
            // 获取方法参数
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                // 过滤掉HttpServletRequest、HttpServletResponse等不需要记录的参数
                StringBuilder params = new StringBuilder();
                for (Object arg : args) {
                    if (arg != null && 
                        !(arg instanceof HttpServletRequest) && 
                        !(arg instanceof jakarta.servlet.http.HttpServletResponse)) {
                        if (params.length() > 0) {
                            params.append(", ");
                        }
                        params.append(objectMapper.writeValueAsString(arg));
                    }
                }
                return params.toString();
            }
        } catch (Exception e) {
            log.warn("获取请求参数失败", e);
        }
        return "";
    }

    /**
     * 提取业务ID
     */
    private String extractBusinessId(ProceedingJoinPoint joinPoint, OperationLog operationLog) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                // 根据操作类型和业务类型智能提取ID
                String businessType = operationLog.businessType();
                
                // 对于删除、更新、查询操作，通常第一个参数是ID
                if ("DELETE".equals(operationLog.type()) || 
                    "UPDATE".equals(operationLog.type()) || 
                    "QUERY".equals(operationLog.type())) {
                    Object firstArg = args[0];
                    if (firstArg instanceof Long) {
                        return firstArg.toString();
                    } else if (firstArg instanceof String) {
                        return (String) firstArg;
                    }
                }
                
                // 对于新增操作，尝试从参数对象中提取ID字段
                if ("CREATE".equals(operationLog.type())) {
                    for (Object arg : args) {
                        if (arg != null && 
                            !(arg instanceof HttpServletRequest) && 
                            !(arg instanceof jakarta.servlet.http.HttpServletResponse)) {
                            try {
                                // 尝试通过反射获取id字段
                                java.lang.reflect.Field idField = arg.getClass().getDeclaredField("id");
                                idField.setAccessible(true);
                                Object idValue = idField.get(arg);
                                if (idValue != null) {
                                    return idValue.toString();
                                }
                            } catch (Exception e) {
                                // 忽略反射异常，继续尝试其他方式
                            }
                        }
                    }
                }
                
                // 如果以上方式都失败，尝试从第一个参数中提取
                Object firstArg = args[0];
                if (firstArg instanceof Long) {
                    return firstArg.toString();
                } else if (firstArg instanceof String) {
                    return (String) firstArg;
                }
            }
        } catch (Exception e) {
            log.warn("提取业务ID失败", e);
        }
        return null;
    }

    /**
     * 提取业务名称
     */
    private String extractBusinessName(ProceedingJoinPoint joinPoint, OperationLog operationLog) {
        // 可以根据实际业务需求实现业务名称的提取逻辑
        // 这里简单返回操作名称
        return operationLog.name();
    }

    /**
     * 获取当前用户信息
     */
    private SysUserEntity getCurrentUser(Long userId) {
        try {
            if (userId != null) {
                return sysUserService.getById(userId);
            }
        } catch (Exception e) {
            log.warn("获取当前用户信息失败，用户ID: {}", userId, e);
        }
        return null;
    }

    /**
     * 获取当前登录用户ID
     */
    private Long getCurrentUserId() {
        try {
            // 使用Sa-Token获取当前登录用户ID
            if (cn.dev33.satoken.stp.StpUtil.isLogin()) {
                return cn.dev33.satoken.stp.StpUtil.getLoginIdAsLong();
            }
        } catch (Exception e) {
            log.warn("获取当前用户ID失败", e);
        }
        return null;
    }
}